/** \file main.c
 *  Test the grammer written, Adapted from Jim Idle which is adpated from Java equivalent
 *  example, by Terence Parr
 * \author Ameen Jaber
 * \author Mohamad Noureddine
 * \author Mohamed Sabra
 * \brief Main program of the entire project, it's where everything happens. 
 */

/** 
 * \mainpage TripleP Documentation
 * \author Ameen Jaber
 * \author Mohamad Noureddine
 * \author Mohamed Sabra
 * \date 27-5-2011
 */
#include <defs.h>
#include <visit.h>
#include <iostream>
#include <TriplePLexer.h>
#include <TriplePParser.h>
#include <InDataLexer.h>
#include <InDataParser.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <getopt.h>
#include <boost/config.hpp>
#include <boost/graph/adjacency_list.hpp>
#include <boost/unordered_map.hpp>
#include <InDGraph.h>
#include <execution.h>

using namespace std;

std::string elabels[] ={"If", "Then","Else","continueCond", "ContinueBody","at"};//!< operation labels for edges
std::string nlabels[] ={"+","-","*","/","%","^","+","-","~","at","=",">","<",">=","<=","AND","OR","==","FOR","IF","THEN","ELSE","CONTINUE","~","INTERSECTION","CARDINALITY"}; //!< operation labels for nodes
 
/** 
 * \brief traverse and generate the graph 
 */
void traverseGraph(TPGraph_t* //!< Graph of the code written
		   ,revTPTable_t * //!< maps node_ID to variable_ID
		   , TPTable_t * //!< maps variable_ID to node_ID
		   );


// Main entry point for this example
//
int ANTLR3_CDECL
main	(int argc, char *argv[])
{
  //////////// TripleP ////////////////
  pANTLR3_UINT8 fName;
  pANTLR3_INPUT_STREAM input;
  pTriplePLexer lxr;
  pANTLR3_COMMON_TOKEN_STREAM tstream;
  pTriplePParser psr;

  ///////////// InData  /////////////////
  pANTLR3_UINT8 _fName;
  pANTLR3_INPUT_STREAM _input;
  pInDataLexer _lxr;
  pANTLR3_COMMON_TOKEN_STREAM _tstream;
  pInDataParser _psr;

  bool dotFile=false;
  bool translate=false;
  string inputFile="";
  string inputState="";
  string outState="";
  int opt;

  while((opt = getopt(argc, argv, "i:dt:o:T"))!= -1){
    switch (opt) {
    case 'i':
      inputFile+=optarg;
      fName=(pANTLR3_UINT8)(inputFile.c_str());
      break;
    case 'd':
      dotFile=true;
      break;
    case 't':
      inputState+=optarg;
      _fName=(pANTLR3_UINT8)(inputState.c_str());
      break;
    case 'o':
      outState+=optarg;
      break;
    case 'T':
      translate=true;
      break;
    default:
      fprintf(stderr, "Usage: %s [-i {filename}] [-d generate dot] [-T translate] [-t {Input State}] [-o {Output State}]\n",
	      argv[0]);
      exit(EXIT_FAILURE);

    }
  }
  /////////// TripleP /////////////
  input	= antlr3AsciiFileStreamNew(fName);
  if ( input == NULL)
    {
      fprintf(stderr, "Failed to open file %s\n", (char *)fName);
      exit(1);
    }
  lxr= TriplePLexerNew(input); // CLexerNew is generated by ANTLR

  // Need to check for errors
  //
  if ( lxr == NULL )
    {
      fprintf(stderr, "Unable to create the lexer due to malloc() failure1\n");
      exit(1);
    }
  tstream = antlr3CommonTokenStreamSourceNew(ANTLR3_SIZE_HINT, TOKENSOURCE(lxr));

  if (tstream == NULL)
    {
      fprintf(stderr, "Out of memory trying to allocate token stream\n");
      exit(1);
    }

  // Finally, now that we have our lexer constructed, we can create the parser
  //
  psr = TriplePParserNew(tstream);  // CParserNew is generated by ANTLR3

  if (psr == NULL)
    {
      fprintf(stderr, "Out of memory trying to allocate parser\n");
      exit(ANTLR3_ERR_NOMEM);
    }
  TriplePParser_translation_unit_return a=psr->translation_unit(psr);
 /////////// InData  /////////////
  _input = antlr3AsciiFileStreamNew(_fName);
  if ( _input == NULL)
    {
      fprintf(stderr, "Failed to open file %s\n", (char *)_fName);
      exit(1);
    }
  _lxr= InDataLexerNew(_input); // CLexerNew is generated by ANTLR

  // Need to check for errors
  //
  if ( _lxr == NULL )
    {
      fprintf(stderr, "Unable to create the lexer due to malloc() failure1\n");
      exit(1);
    }
  _tstream = antlr3CommonTokenStreamSourceNew(ANTLR3_SIZE_HINT, TOKENSOURCE(_lxr));

  if (_tstream == NULL)
    {
      fprintf(stderr, "Out of memory trying to allocate token stream\n");
      exit(1);
    }

  // Finally, now that we have our lexer constructed, we can create the parser
  //
  _psr = InDataParserNew(_tstream);  // CParserNew is generated by ANTLR3

  if (_psr == NULL)
    {
      fprintf(stderr, "Out of memory trying to allocate parser\n");
      exit(ANTLR3_ERR_NOMEM);
    }

  varTable_t * b=_psr->translation_unit(_psr);
  
  //////////////////////////////

  graphStruct new_graph;

  TPGraph_t * tgraph = a.rgraph;
  TPTable_t * Var_ID = a.rTtable;
  revTPTable_t * Var_name = a.rrevTtable;
  GraphTable_t * Graph_name = a.rgTable;
  
  //Our graph
  new_graph.graph=tgraph;
  new_graph.Vname=Var_name; 
  new_graph.VID=Var_ID;

  // if(dotFile)
  // {
  traverseGraph(new_graph.graph,new_graph.Vname, new_graph.VID);
      //}
  
#if 0
  varTable_t::iterator it;
  for(it=b->begin(); it != b->end(); it++) {
    cout<<it->first<<" = ";
    it->second->print();
    cout<<'\n';
  }
#endif 

  /////////////// Execute the code ////////////
  bool done;
  done=execution(& new_graph,b,Graph_name, a.raMap);
  //pppsequence * b = (pppsequence*)((it)->second);
  //ppprelation * re = (ppprelation*)((it)->second);
  //re->print();
  // std::cout << "B is of size " << b->data->size() << std::endl;
  //std::vector<object *>::iterator _it;
  //std::vector<Pair_t*>::iterator _it;
  //for (_it = b->data->begin() ; _it != b->data->end() ; _it++) {
    //pppsequence * v = (pppsequence*)(*_it);
  //  std::cout << "Size = " << ((pppsequence*)(*_it))->data->size() << std::endl;
  //}
  //  std::cout << re->data->size() << std::endl;
  //std::cout << (*(re->data))[1]->first->val << " , " << (*(re->data))[1]->second->val << std::endl;
  //pppsequence * subb = (pppsequence*)((*(b->data))[0]);
  //ppprelation * subb = (ppprelation*)((*(b->data))[0]);
  //std::cout << "---> set b has an internal set having a value " << (*(subb->data))[0]->val << std::endl;
  //std::cout << "---> relation b has the first element as follows " << (*(subb->data))[0]->first << std::endl;
  //#endif
  psr	    ->free  (psr);	    psr = NULL;
  tstream ->free  (tstream);	    tstream = NULL;
  lxr	    ->free  (lxr);	    lxr = NULL;
  input   ->close (input);	    input = NULL;

  _psr	    ->free  (_psr);	    _psr = NULL;
  _tstream ->free  (_tstream);	    _tstream = NULL;
  _lxr	    ->free  (_lxr);	    _lxr = NULL;
  _input   ->close (_input);	    _input = NULL;
  return 0;
}

void traverseGraph(TPGraph_t * Tgraph, revTPTable_t * Vname, TPTable_t * VID)
{
  boost::graph_traits<TPGraph_t>::vertex_iterator v, vend;
  for (tie(v, vend) = vertices(*Tgraph); v != vend; ++v) {
    int vID = *v;
    int val = (*Tgraph)[*v].value;
    int opID = (*Tgraph)[*v].op;
    string varID="";
    std::map<int,string>::iterator it;
    it=(*Vname).find(*v);
    if(it!=(*Vname).end()){
      varID=(*Vname)[*v];
    }
    string label="Program";
    if((*Tgraph)[*v].op >= 11)
      {
	int i = (*Tgraph)[*v].op; 
	label=nlabels[i-11].c_str();
      }
    visitNode(vID,val,opID,varID,label);
  }
  for (tie(v, vend) = vertices(*Tgraph); v != vend; ++v) {
    boost::graph_traits<TPGraph_t>::out_edge_iterator e,eend;
    for(tie(e,eend) = out_edges(*v,*Tgraph); e!=eend; ++e){
      int vSource = source(*e,*Tgraph);
      int vTarget = target(*e,*Tgraph);
      int opSource = (*Tgraph)[vSource].op;
      int opTarget = (*Tgraph)[vTarget].op;
      int elabel = (*Tgraph)[*e].label;
      string label = "label";
      //string label(elabels[(*Tgraph)[*e].label].c_str());
      visitEdge(vSource,vTarget,opSource,opTarget,elabel,label);
    }
  }
}
